package user

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"likeadmin/client/schemas/req"
	"likeadmin/client/schemas/resp"
	"likeadmin/config"
	"likeadmin/core"
	"likeadmin/core/response"
	"likeadmin/model/client"
	"likeadmin/util"
	"net/http"
	"runtime/debug"
	"strconv"
	"time"
)

type ISystemLoginService interface {
	Login(c *gin.Context, req *req.ClientLoginReq) (res resp.ClientUserLoginResp, e error)
	Logout(req *req.ClientLogoutReq) (e error)
}

// NewSystemLoginService 初始化
func NewSystemLoginService(db *gorm.DB, adminSrv ISystemAuthAdminService) ISystemLoginService {
	// 初始化全局队列服务（如果尚未初始化）
	queueService := util.NewQueueService(core.Redis)
	return &systemLoginService{
		db:           db,
		adminSrv:     adminSrv,
		queueService: queueService, // 注入队列服务
	}
}

// systemLoginService 系统登录服务实现类
type systemLoginService struct {
	db           *gorm.DB
	adminSrv     ISystemAuthAdminService
	queueService *util.QueueService // 添加队列服务字段
}

// WechatSessionResp 微信 session 返回结构
type WechatSessionResp struct {
	OpenID     string `json:"openid"`
	SessionKey string `json:"session_key"`
	UnionID    string `json:"unionid,omitempty"`
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
}

// WechatUserInfo 微信用户信息结构
type WechatUserInfo struct {
	OpenID   string `json:"openid"`
	Nickname string `json:"nickname"`
	Sex      int    `json:"sex"`
	Avatar   string `json:"headimgurl"`
	// 其他需要的字段
}

// 获取微信 session
func (loginSrv systemLoginService) getWechatSession(code string, appConfig client.AppConfigs) (*WechatSessionResp, error) {

	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		appConfig.AppId, appConfig.AppSecret, code)

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var sessionResp WechatSessionResp
	if err := json.NewDecoder(resp.Body).Decode(&sessionResp); err != nil {
		return nil, err
	}

	if sessionResp.ErrCode != 0 {
		return nil, errors.New(sessionResp.ErrMsg)
	}

	return &sessionResp, nil
}

// 获取微信用户信息
func (loginSrv systemLoginService) getWechatUserInfo(accessToken, openID string) (*WechatUserInfo, error) {
	url := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
		accessToken, openID)

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var userInfo WechatUserInfo
	if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
		return nil, err
	}

	return &userInfo, nil
}

// Login 登录
func (loginSrv systemLoginService) Login(c *gin.Context, req *req.ClientLoginReq) (res resp.ClientUserLoginResp, e error) {

	var deviceId string
	var sessionData *WechatSessionResp

	ip := util.IpUtil.GetRealIp(c)
	packageName := c.Request.Header.Get("packagename")
	version := c.Request.Header.Get("versionname")
	userAgent := c.Request.Header.Get("User-Agent")

	if req.Code == "testxxxxxx" {
		sessionData = &WechatSessionResp{
			OpenID: "testxxxxxx",
		}
	} else {
		// 调用微信接口获取 session_key 和 openid
		var err error
		// 获取支付配置
		appConfig, err := util.ConfigUtil.AppConfigCache(loginSrv.db, packageName)
		if e = response.CheckErrDBNotRecord(err, "获取配置 app err"); e != nil {
			return
		}

		sessionData, err = loginSrv.getWechatSession(req.Code, appConfig)
		if err != nil {
			e = response.CheckErr(err, "微信登录失败")
			return
		}
	}

	var source client.Source
	err := loginSrv.db.Model(&client.Source{}).Where("source_id = ? AND package_name = ?", req.SourceId, packageName).Limit(1).First(&source).Error
	if e = response.CheckErrDBNotRecord(err, "Source First err！"); e != nil {
		req.SourceId = ""
	}

	// 投放厂商id
	var channel uint8

	// 使用微信用户信息更新或创建用户
	deviceId = sessionData.OpenID

	clientUser, err := loginSrv.adminSrv.FindByUsername(deviceId)

	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {

		if source.Channel > 0 {
			channel = source.Channel
		}
		clientUser.DeviceId = deviceId
		clientUser.IsDelete = 0
		clientUser.IsDisable = 0
		clientUser.Channel = channel // 1=头条, 2=百度, 3=uc, 4=oppo, 5=vivo, 6=快手
		clientUser.Provider = req.Provider
		clientUser.Model = req.Model
		clientUser.SourceId = source.SourceId
		clientUser.AccountId = source.AccountId
		clientUser.CreaterID = source.CreaterID
		clientUser.RegisterUa = userAgent
		clientUser.RegisterIp = ip
		clientUser.LastLoginIp = ip
		clientUser.Version = version
		clientUser.PackageName = packageName
		clientUser.Sn = util.UitlSnow.SnowId()
		clientUser.Nickname = util.StringUtil.NicknameCreate("")

		clientUser.Avatar = util.UrlUtil.ToRelativeUrl("/api/static/backend_avatar.png")

		// 获取城市信息
		clientUser.CityInfo = util.IpUtil.HttpAiwenCity(ip)

		// 使用 GORM 的Clauses方法
		err = loginSrv.db.Clauses(clause.OnConflict{
			Columns:   []clause.Column{{Name: "device_id"}},
			DoNothing: true, // 或者使用 DoUpdates 来更新已有记录
		}).Create(&clientUser).Error

		if err != nil {
			e = response.CheckErr(err, "Add Create err")
			return
		}

		err = loginSrv.queueService.AddOrderMessage(util.OrderMessage{
			Type:     "active",
			OrderID:  clientUser.DeviceId,
			DeviceId: clientUser.DeviceId,
			Complete: false,
			Time:     time.Now(),
		}, 30)

		if err != nil {
			core.Logger.Errorf("添加激活消息到队列失败: %v", err)
		}
	} else {

		updates := client.ClientUser{
			LastLoginIp:   ip,
			LastLoginTime: time.Now().Unix(),
			LastUa:        userAgent,
			VersionLast:   version,
		}

		if req.SourceId != "" && req.SourceId != clientUser.SourceId {
			updates.SourceId = req.SourceId
			updates.UpdateTime = time.Now().Unix()
		}
		// 更新登录信息
		err = loginSrv.db.Model(&clientUser).Updates(updates).Error
		if err != nil {
			if e = response.CheckErr(err, "Login Updates err"); e != nil {
				return
			}
		}
	}

	if clientUser.IsDelete == 1 {
		e = response.LoginAccountError
		return
	}
	if clientUser.IsDisable == 1 {
		e = response.LoginDisableError
		return
	}

	defer func() {
		if r := recover(); r != nil {
			switch r.(type) {
			// 自定义类型
			case response.RespType:
				panic(r)
			// 其他类型
			default:
				core.Logger.Errorf("stacktrace from panic: %+v\n%s", r, string(debug.Stack()))
				panic(response.Failed)
			}
		}
	}()

	token := util.ToolsUtil.MakeToken()
	adminIdStr := strconv.FormatUint(uint64(clientUser.ID), 10)

	// 缓存登录信息
	util.RedisUtil.Set(config.ClientConfig.BackstageTokenKey+token, adminIdStr, 7200)
	loginSrv.adminSrv.CacheAdminUserByUid(clientUser.ID)

	// 返回登录信息
	return resp.ClientUserLoginResp{Token: token}, nil
}

// Logout 退出
func (loginSrv systemLoginService) Logout(req *req.ClientLogoutReq) (e error) {
	util.RedisUtil.Del(config.ClientConfig.BackstageTokenKey + req.Token)
	return
}
